//
// Process.cpp
// Usage: Process object
// CreateDate: 2009-04-05
// Author: MaJiuyue
//
#include "Process.h"
#include <SCI.h>
#include <errno.h>

Process::Process(pid_t pid, int priority, int umbox_size)
	: m_PID(pid), m_Priority(priority), mbox(umbox_size)
{
	m_ProcessStatus = PS_CREATING;

	// Create a running thread
	Thread * thread = new Thread(this);
	// Add it to process' thread list
	m_Threads.insertLast(thread);
}

Process::Process(Process& target, pid_t child_pid)
	: m_PID(child_pid),
	  m_Priority(target.m_Priority), 
	  m_Context(target.m_Context),
	  mbox(target.mbox),
	  FCB(target.FCB)
{
	m_ProcessStatus = target.m_ProcessStatus;
	
	// Dumplicate "target process"'s thread list
	Thread * parent_thread = target.m_Threads.iterateFirst();
	while(target.m_Threads.iterateIsValid())
	{
		m_Threads.insertLast(new Thread(*parent_thread, this));
		parent_thread = target.m_Threads.iterateNext();
	}
}

Process::~Process()
{
	// Delete all thread
	Thread * thread = NULL;
	while(thread = m_Threads.removeFirst())
		delete thread;
}

void Process::SwitchContext()
{
	m_Context.SwitchContext();	
}

Process * Process::CreateChildProcess(pid_t child_pid)
{
	Process *child = new Process(*this,child_pid);
	this->m_Childs.insertLast(child);
	child->m_Parent = this;
	return child;
}

Process * GetCurrentProcess()
{
	Process * p;
	__asm__ __volatile__(
		"movl $0xFFFFE000, %%ecx\t\n"
		"andl %%esp, %%ecx\t\n"
		"movl (%%ecx), %%eax"
		:"=a"(p)
	);
	return p;	
}

int Process::Exit()
{
	//set dead state, panduan parent shifou waitpid,if yes delete himself then wakeup parent,fanhui para,no zhijie exit.
	
	this->SetProcessStatus(PS_DEAD);

	Resource * resSchedule = ResourceManager.RequestResource(
		ServiceCallInterface::Scheduler::ResourceName
	);

	if (this->GetParent()->GetWaitPID() == this->GetPID())
	{	
		resSchedule->CallSCI(
			ServiceCallInterface::Scheduler::SCIID_WakeUp,
			this->GetParent()->GetPID()
		);

		u32 ebx = this->GetThread()->GetRegisterValue(REGS_EBX);
		this->GetParent()->GetThread()->SetRegisterValue(REGS_EAX, ebx);

		return 1;
	}

	return 0;
}

int Process::WaitPID(pid_t pid)
{
	//panduan shifou wei child process,shi panduan child process state,PS_DEAD,quchu ebx -> eax,destroy itself,fou zuse himself
	bool b = false;
	Process *child = NULL;
	Resource *res = NULL;

	m_Childs.iterateFirst();
	while (m_Childs.iterateIsValid())
	{
		if ( (m_Childs.iterateGetValue())->GetPID() == pid )
		{
			b = true;
			child = m_Childs.iterateGetValue();
		}
	}	

	if (!b)
		return 0;
	else
	{
		if (child->GetProcessStatus()==PS_DEAD)
		{
			u32 ebx = child->GetThread()->GetRegisterValue(REGS_EBX);
			GetThread()->SetRegisterValue(REGS_EAX, ebx);
			
			res = ResourceManager.RequestResource(
				ServiceCallInterface::ProcessManager::ResourceName
			);						 
			res->CallSCI(ServiceCallInterface::ProcessManager::SCIID_DestroyProcess,
				pid
			);
		}
		else
		{
			res=ResourceManager.RequestResource(
				ServiceCallInterface::Scheduler::ResourceName
			);
			res->CallSCI(ServiceCallInterface::Scheduler::SCIID_Block,
				this->GetPID()
			);
				
		}
		return 1;
	}
}

